import openpyxl
import io
import json
from django.db import transaction
from datetime import datetime

class ExcelUtils:
    @staticmethod
    def get_sheet_names(file_content):
        """
        获取Excel文件中的所有工作表名称
        
        Args:
            file_content: 文件内容（字节流）
        
        Returns:
            list: 工作表名称列表
        """
        wb = openpyxl.load_workbook(io.BytesIO(file_content))
        return wb.sheetnames

    @staticmethod
    def get_headers(file_content, sheet_name, start_row=1):
        """
        获取指定工作表和开始行的表头信息
        
        Args:
            file_content: 文件内容（字节流）
            sheet_name: 工作表名称
            start_row: 表头开始行号（默认为1）
        
        Returns:
            list: 表头列表
        """
        wb = openpyxl.load_workbook(io.BytesIO(file_content))
        sheet = wb[sheet_name]
        
        headers = []
        header_row = sheet[start_row]
        for cell in header_row:
            if cell.value:
                headers.append(cell.value.strip())
                
        return headers

    @staticmethod
    def get_data_preview(file_content, sheet_name, start_row=1, preview_rows=5):
        """
        获取数据预览
        
        Args:
            file_content: 文件内容（字节流）
            sheet_name: 工作表名称
            start_row: 数据开始行号（默认为1）
            preview_rows: 预览行数（默认为5）
        
        Returns:
            dict: 包含表头和预览数据的字典
        """
        wb = openpyxl.load_workbook(io.BytesIO(file_content))
        sheet = wb[sheet_name]
        
        # 获取表头
        headers = []
        header_row = sheet[start_row]
        for cell in header_row:
            headers.append(cell.value.strip() if cell.value else '')
        
        # 获取预览数据
        preview_data = []
        data_start_row = start_row + 1
        max_row = min(sheet.max_row, data_start_row + preview_rows - 1)
        
        for row_idx in range(data_start_row, max_row + 1):
            row_data = []
            for col_idx in range(len(headers)):
                cell = sheet.cell(row=row_idx, column=col_idx + 1)
                row_data.append(cell.value)
            preview_data.append(row_data)
        
        return {
            'headers': headers,
            'preview_data': preview_data
        }

    @staticmethod
    def import_data(file_content, sheet_name, start_row, field_mappings, import_handler, user=None):
        """
        执行数据导入
        
        Args:
            file_content: 文件内容（字节流）
            sheet_name: 工作表名称
            start_row: 数据开始行号
            field_mappings: 字段映射关系（Excel列名到系统字段的映射）
            import_handler: 导入处理函数，接收行数据和用户信息，返回是否成功和错误消息
            user: 用户信息
        
        Returns:
            dict: 导入结果，包含成功数量、失败数量和错误消息
        """
        wb = openpyxl.load_workbook(io.BytesIO(file_content))
        sheet = wb[sheet_name]
        
        success_count = 0
        error_count = 0
        error_messages = []
        
        # 获取表头
        headers = []
        header_row = sheet[start_row]
        for cell in header_row:
            headers.append(cell.value.strip() if cell.value else '')
        
        # 构建表头到列索引的映射
        header_to_col = {header: idx for idx, header in enumerate(headers)}
        
        # 导入数据，使用事务确保原子性
        with transaction.atomic():
            # 从表头下一行开始读取数据
            data_start_row = start_row + 1
            max_row = sheet.max_row
            
            for row_idx in range(data_start_row, max_row + 1):
                try:
                    # 构建行数据字典
                    row_data = {}
                    for excel_col, sys_field in enumerate(field_mappings):
                        if sys_field:
                            # 找到对应的Excel列名
                            header = headers[excel_col] if excel_col < len(headers) else ''
                            if header in header_to_col:
                                cell = sheet.cell(row=row_idx, column=excel_col + 1)
                                row_data[sys_field] = cell.value
                    
                    # 调用导入处理函数
                    success, error_msg = import_handler(row_data, user)
                    
                    if success:
                        success_count += 1
                    else:
                        error_count += 1
                        error_messages.append(f'第{row_idx}行：{error_msg}')
                    
                except Exception as e:
                    error_count += 1
                    error_messages.append(f'第{row_idx}行：导入失败 - {str(e)}')
        
        return {
            'success_count': success_count,
            'error_count': error_count,
            'error_messages': error_messages
        }